var log = console.log;

var CardPool = require('../../util/cardPool.js');
var exp = module.exports;

var cardPoolObj = {};
var resultListObj = {};

var reCards;

// 为一个房间初始化牌局
function initCardPool(rid) {
    var cardPool;
    if (!cardPoolObj[rid]) {
        cardPool = new CardPool().get(1, 54);
        cardPoolObj[rid] = cardPool;
        resultListObj[rid] = [];
    }
    return cardPoolObj[rid];
}

function max(arr) {
    var val = arr[0];
    var idx = 0;
    for (var i = 0, len = arr.length; i < len; i++) {
        if (val < arr[i]) {
            val = arr[i];
            idx = i;
        }
    }
    return { val: val, idx: idx };
}

function leftPad(strs, len, str) {
    if (!len || len <= 0) {
        return strs;
    }
    var l = strs.length;
    if (l >= len) {
        return strs;
    }
    for (var i = l; i < len; i++) {
        strs = str + strs;
    }
    return strs;
}

function maxCards(cards) {
    var cardWeight = [];
    var suit = {
        A: '00',
        B: '01',
        C: '10',
        D: '11'
    };
    var weight = 0, index = -1;
    var num;
    cards.forEach(function (val, idx) {
        cardWeight[idx] = {};
        cardWeight[idx].idx = idx;
        cardWeight[idx].num = leftPad(parseInt(cards[idx].substring(1)).toString(2), 4, '0');
        cardWeight[idx].suit = suit[cards[idx].substring(0, 1)];
        cardWeight[idx].weight = cardWeight[idx].num + cardWeight[idx].suit;
        cardWeight[idx].weight = parseInt(cardWeight[idx].weight, 2);
        if (cardWeight[idx].weight > weight) {
            weight = cardWeight[idx].weight;
            index = cardWeight[idx].idx;
        }
    });

    if (cards.indexOf('X1') > -1) {
        num = '1111';
        suit = '00';
        index = cards.indexOf('X1');
    }
    else if (cards.indexOf('X0') > -1) {
        num = '1110';
        suit = '00';
        index = cards.indexOf('X0');
    }
    else {
        num = cardWeight[index].num;
        suit = cardWeight[index].suit;
    }

    return {
        num: num,
        suit: suit,
        idx: index
    };

    // log(weight, index);
    // log(cards[index]);
    // log(cardWeight);
}

function next(rid) {

    var cardPool;
    var result = {};

    // // 初始化牌池信息，结果列表信息
    // if (!cardPoolObj[rid]) {
    // 	cardPool = initCardPool(rid);
    // } else {
    // 	cardPool = cardPoolObj[rid];
    // }

    // if (cardPool.length < 25) {
    // 	cardPool = cardPool.concat(new CardPool().get(8, 54));
    // 	cardPoolObj[rid] = cardPool;
    // }

    cardPool = new CardPool().get(1, 54);
    var tmpCardPool = cardPool.slice();
    // log(cardPool.length);

    if (!resultListObj[rid]) {
        resultListObj[rid] = [];
    }

    var player = []; // 5个玩家
    // 发牌
    for (var i = 0; i < 5; i++) {
        player[i] = {};
        player[i].cards = [];
        for (var k = 0; k < 5; k++) {
            var idx = (i * 5) + k;  // reCards 的索引值
            player[i].cards.push(cardPool.shift());
            // 下面的用于换牌
            if (reCards[idx]) {
                player[i].cards.pop();
                player[i].cards.push(reCards[idx]);
            }
        }

        player[i].rel = countNiu(player[i].cards);
        // player[i].rel.cardPool = tmpCardPool;
    }

    // log(player);

    result.player = player;

    result.odd = getOdds(player);

    // var result = {};
    return result;
}


// 输入五张牌，计算牛
function countNiu(cards) {
    var tmp;

    var rel = {
        card: '',
        niu: -1,
        special: '',
        specialCard: '',
        str: ''
    };

    var cardRealNum = [];
    var cardNum = [];
    for (var i = 0; i < 5; i++) {
        tmp = parseInt(cards[i].substring(1));
        cardRealNum.push(tmp);
        tmp = tmp > 9 ? 0 : tmp;
        cardNum.push(tmp);
    }

    // 大小王的位置
    var x0 = cards.indexOf('X0');
    var x1 = cards.indexOf('X1');

    /// 检查是否有牛
    function checkNiu(i, j, k) {
        return cardNum[i] + cardNum[j] + cardNum[k];
    }

    // 检查特殊牌型
	/**
	 * 牌型：炸弹> 五小 > 五花 > 四花 > 牛牛 > 有牛 > 无牛
	 * 特殊牌型：炸弹 五小 五花 四花
	 * 炸弹：1.4张相同 2.三张 3.两张
	 * 五小：1.都小于5且相加小于等于10 2.都小于5且相加小于等于9 3.都小于5且相加小于等于8
	 * 五花：1.5都大于10 2.4都大于10 3.3都大于10
	 * 四花：1.四个大于10 2.三个大于10 3.两个大于10
	 * 四种牌型从大到小，出现大的就不算小的
	 * 如果出现了特殊牌型，就不需要再检测是否有牛
	 * 一共 4 * 3 = 12 种情况！
	 * 把各种牌型的限制条件提前抽象为参数，减少了很多行重复代码
	 */
    function checkSpecial(x0, x1) {
        // 1.不出现王的情况 2.出现一个王的情况 3.出现两个王的情况
        var i = 0, len = 5;
        var tmpObj = {}, tmpList = [], zdList = [];
        var count = 0; // 计算五小
        var wx = true;  // 五小
        var wh = true;  // 五花
        var sh = true;  // 四花
        var check = {
            zd: 4,
            wx: 10,
            wh: 5,
            sh: 4
        };  // 正常没有大小王时候的情景

        if ((x0 < 0 && x1 > -1) || (x0 > -1 && x1 < 0)) {
            check = {
                zd: 3,
                wx: 9,
                wh: 4,
                sh: 3
            };
        } // 一个王的情况
        if (x0 > -1 && x1 > -1) {
            check = {
                zd: 2,
                wx: 8,
                wh: 3,
                sh: 2
            };
        }  // 两个王的情况

        // if (x0 < -1 && x1 < -1) {}
        for (; i < len; i++) {
            if (i === x0 || i === x1) {
                continue;  // 大小王不算
            }
            if (!tmpObj[cardRealNum[i]]) {
                tmpObj[cardRealNum[i]] = 1;
                zdList.push(cardRealNum[i]);
            }
            else {
                tmpObj[cardRealNum[i]]++;
            }
            tmpList.push(cardRealNum[i]);
        }
        // 1.1 炸弹
        if (zdList.length === 2) {
            // 王牌之外只有两张牌相同的牌
            if (tmpObj[tmpList[0]] === check.zd || tmpObj[tmpList[1]] === check.zd) {
                // 其中一张出现了(4-王牌数量)次才是炸弹
                rel.special = 'zd';  // 炸弹确定
                // 确定炸弹牌是几
                if (tmpObj[tmpList[0]] === check.zd) {
                    rel.specialCard = tmpList[0];
                }
                else {
                    rel.specialCard = tmpList[1];
                }
                // 确定炸弹牌是哪几张
                for (var idx in cardRealNum) {
                    if (cardRealNum[idx] === rel.specialCard || cards[idx].indexOf('X') > -1) {
                        // 作炸弹的牌或者是王的牌
                        rel.card += idx;
                    }
                }
                return;  // 确定一种牌型之后，可以直接返回了
            }
        }
        // 1.2 五小
        wx = true;
        for (var v of tmpList) {
            if (v >= 5) {
                wx = false;
                break;
            }
            count += v;
        }
        if (count > check.wx) {
            wx = false;
        }
        if (wx) {
            rel.special = 'wx';  // 五小确定
            rel.card = '01234';
            return;
        }
        // 1.3 五花
        wh = true;
        count = 0;
        for (v of tmpList) {
            if (v <= 10) {
                wh = false;
                break;
            }
            else if (v > 10) {
                count++;
            }
        }
        if (count < check.wh) {
            wh = false;
        }
        if (wh) {
            rel.special = 'wh';  // 五花牌型确定
            rel.card = '01234';
            return;
        }
        // 1.4 四花
        count = 0;
        sh = true;
        for (v of tmpList) {
            if (v > 10) {
                count++;
            }
        }
        if (count < check.sh) {
            sh = false;
        }
        if (sh) {
            rel.special = 'sh';  // 四花确定
            // 确定四花牌是哪几张
            for (idx in cardRealNum) {
                if (cardRealNum[idx] > 10 || cards[idx].indexOf('X') > -1) {
                    // 作炸弹的牌或者是王的牌
                    rel.card += idx;
                }
            }
        }

    }

    // 有王牌的情况下计算牛数
	/**
	 * 粗暴的算法：
	 * 如果只有一个王，就把这个王替换为0-9，再用getNiu2来循环计算最大的牛
	 * 如果有两个王，也就是0-0到9-9总共55种情况
	 * 计算复杂，也可能太耗时
	 * 优雅的算法：
	 * 如果只有一个王，那么就是四个数中两两相加最大的牛数。 如：1,7,王,6,12就只能是牛八。
	 * 四个中如果有两个数相加为10,那么就是牛牛，否则就是4个数中两两相加最大的
	 * 如果有两个王，如1,7,0,0,12,那就是牛牛，因为一个王可以和随便两张牌组成牛，另一个王又可以和随便一张牌组成牛牛！
	 */
    function getNiu1(x0, x1) {
        var i1 = -1,
            i2 = -1;
        var i = 0,
            j = 0;
        var count = 0;
        var idx = -1;

        if (x0 > -1 && x1 > -1) {
            // 两个王的情况
            idx = x0; // 王牌要加上
            rel.card += idx;
            for (i = 0; i < 5; i++) {
                if (count < 2) {
                    // 获取两张不是王的牌的序号
                    if (i !== x0 && i !== x1) {
                        rel.card += i;
                        count++;
                    }
                }
                else {
                    break;
                }
            }
            rel.niu = 0;
        }
        else {
            // 一个王的情况
            if (x0 > -1) {
                idx = x0;
            }
            else {
                idx = x1;
            }
            // 检查两两相加的最大值和各自的索引
            var rec = {};
            var tmpCount, niuCount = 1,
                idx1, idx2;
            var getNiuniu = false;
            var tmpList = cardNum.slice();
            // tmpList.splice(idx, 1);
            for (i = 0; i < 5; i++) {
                if (i === idx) {
                    // 王牌所在的位置不参与计算
                    continue;
                }
                if (getNiuniu) {
                    break;
                }
                for (j = 1; j < 5; j++) {
                    if (j === i || j === idx) {
                        // 王牌所在的位置不参与计算
                        // 也不能用两张相同的牌相加
                        continue;
                    }
                    tmpCount = (tmpList[i] + tmpList[j]) % 10;
                    if (tmpCount === 0) {
                        // 得到牛牛直接返回
                        niuCount = 0;
                        idx1 = i;
                        idx2 = j;
                        getNiuniu = true;
                        break;
                    }
                    else {
                        // 得不到牛牛，返回最大的
                        if (niuCount < tmpCount) {
                            niuCount = tmpCount;
                            idx1 = i;
                            idx2 = j;
                        }
                    }
                }
            }
            rel.niu = niuCount;
            // 选出不是idx1和idx2的位置然后和idx组合在一起，组成牛
            var idxList = [0, 1, 2, 3, 4].filter(function (i) {
                return i !== idx && i !== idx1 && i !== idx2;
            });
            idxList.push(idx);
            idxList.sort();
            // var idxList = [idx, idx1, idx2].sort();
            rel.card = rel.card + idxList[0] + idxList[1] + idxList[2];
        }

    }

    // 没有王牌的情况
    function getNiu2(cards) {
        // log(cards);
        // var cards = cards.slice();
        /// 循环检查是否有牛，以及牛数
        for (var i = 0; i <= 2; i++) {
            for (var j = i + 1; j <= 3; j++) {
                for (var k = j + 1; k <= 4; k++) {
                    var s = checkNiu(i, j, k);
                    if (s % 10 === 0) { // 有牛
                        rel.card = '' + i + j + k;

                        rel.niu = cardNum.reduce(function (pre, cur) {
                            return pre + cur;
                        }) % 10;
                    }
                }
            }
        }
        // log('getNiu2 rel');
        // log(rel);
    }

    // 获取权重
    function getWeight() {
        // log('weight begin!');
        var specialWeight = {
            'zd': '111',
            'wx': '110',
            'wh': '101',
            'sh': '100',
            'qt': '000' // 其它
        };  // 特殊牌型权重
        var weight = [];  // 权重
        var weightStr = [];
        // 特殊牌型
        if (rel.special) {
            weight.push(specialWeight[rel.special]);
            weightStr.push(rel.special);
        }
        else {
            weight.push('000');
        }
        // 牛的大小
        if (rel.niu > 0) {  // 一般牛
            weight.push(leftPad(rel.niu.toString(2), 4, '0'));
            weightStr.push('牛' + rel.niu);
        }
        else if (rel.niu === 0 && !rel.special) {  // 牛牛
            weight.push('1111');
            weightStr.push('牛牛');
        }
        else if (rel.special) {  // 特殊牌
            weight.push('1111');
            weightStr.push(rel.special);
        }
        else {
            weight.push('0000');
            weightStr.push('无牛');
        }
        // 最大的牌的牌点 和它的花色  // 这两个是要一起衡量的，不能脱离开
        var maxCard = maxCards(cards);  // 不能直接找最大的数字，要考虑到花色
        if (rel.specialCard) {
            maxCard.num = leftPad(rel.specialCard.toString(2), 4, '0');  // 最大的牌变成了炸弹牌  // 要记得用0补足空位
            maxCard.suit = '00';  // 花色不考虑了？
            // 不考虑花色，反正一副牌不可能出现相同的炸弹，只要是炸弹就一定有大小
        }
        weight.push(maxCard.num);
        weight.push(maxCard.suit);

        weightStr.push(parseInt(maxCard.num, 2));
        weightStr.push(parseInt(maxCard.suit, 2));
        // log(parseInt(weight.join(''), 2));
        rel.weight = parseInt(weight.join(''), 2);
        rel.maxCard = cards[maxCard.idx];
        // rel.weightList = weight;
        // rel.weightStr = weightStr;
    }


    checkSpecial(x0, x1);  // 检查特殊牌型

    // 没有特殊牌型的话计算牛数
    if (!rel.special) {
        /// 检查有王牌的情况  // 没有特殊牌型的情况下检查这个
        if (x0 > -1 || x1 > -1) {
            getNiu1(x0, x1);
        }
        else {
            // 没有王牌的情况
            getNiu2(cards);
        }
    }

    // 计算权重
    getWeight();

    getRelStr();


    function getRelStr() {

        var specialStr = {
            'zd': '炸弹',
            'wx': '五小',
            'wh': '五花',
            'sh': '四花'
        };

        var suitStr = {
            D: '黑',
            C: '红',
            B: '梅',
            A: '方'
        };

        // rel.str += '【';
        // 记录结果：特殊牌型或者牛数
        if (rel.special) {
            rel.niu = 0;
            rel.str += specialStr[rel.special];
        }
        else {
            if (rel.niu === 0) {
                rel.str += '牛牛';
            }
            else if (rel.niu === -1) {
                rel.str += '无牛';
            }
            else {
                rel.str += ('牛' + rel.niu);
            }
        }

        // 记录最大牌或者炸弹型
        if (rel.special === 'zd') {
            rel.str += (',D' + rel.specialCard);
        }
        else {
            // if(rel.maxCard === 'X1') {
            // 	rel.str += ',大王';
            // }
            // else if (rel.maxCard === 'X0') {
            // 	rel.str += ',小王';
            // }
            // else {
            // 	rel.str += (',' + suitStr[rel.maxCard.substring(0, 1)] + rel.maxCard.substring(1));
            // }
            rel.str += (',' + rel.maxCard);
        }
        // rel.str += '】';
    }

    return rel;
}

// 计算赔率
function getOdds(player) {
    // player[0] = {
    // 	cards: ['A3', 'X0', 'C1', 'D13', 'D4'],
    // 	rel:
    // 	{
    // 		card: '123',
    // 		niu: 7,
    // 		special: '',
    // 		specialCard: '',
    // 		weight: 504,
    // 		maxCard: 'X0'
    // 	}
    // };
    var tmpObj = {}, rel, times, odd = {};
    for (i in player) {
        rel = player[i].rel;
        tmpObj[i] = {};
        // 各个赔钱的倍数
        if (rel.niu < 0) {
            times = 1;
        }
        else if (rel.niu === 0) {
            times = 10;
        }
        else {
            times = rel.niu;
        }
        tmpObj[i].times = times;
        tmpObj[i].weight = rel.weight;
    }
    var i, pos, len = player.length;
    var bankerWeight = tmpObj[0].weight;
    var bankerTimes = tmpObj[0].times;
    for (i = 1; i < len; i++) {
        // 对于各个玩家，如果胜了，就是正的，赢钱，否则就是负的，输钱
        // 相同的牛数不可能有相同的最大牌，因此一定会分输赢，不会有平局
        // 因为只有一副牌
        pos = tmpObj[i].weight > bankerWeight ? 1 : -1;
        // 对于各个玩家，如果胜了，胜自己的倍数，输了，输庄家的倍数
        times = pos > 0 ? tmpObj[i].times : bankerTimes;
        odd[i - 1] = pos * times;
    }
    // log(odd);
    return odd;
    // result.odds = odd;
}

reCards = [];

// reCards = [ 'C1', 'A2', 'A1', 'A1', 'D5' ];
// var rel = next(1);
// log(JSON.stringify(rel));
// return;

// var f = false;
// for (var i = 0; ; i++) {
// 	rel = next(1);
// 	// log(rel);
// 	if (f) {
// 		break;
// 	}
// 	for (player of rel.player) {
// 		if (player.rel.special === 'sh') {
// 			// for(v of rel.player) {
// 			// 	log(v.rel.str);
// 			// }
// 			log(player);
// 			// log(JSON.stringify(rel));
// 			// log(player.rel.weight);
// 			f = true;
// 			break;
// 		}
// 	}
// }

// log(rel.player);
// log(rel.player[1].rel);


function getRltList(rid) {
    return resultListObj[rid];
}

function getCardPool(rid) {
    return cardPoolObj[rid];
}

// 如果顶替，就一直顶替
function replaceCards(arr) {
    reCards = arr;
    return true;
}

exp.initCardPool = initCardPool;
exp.next = next;
exp.getRltList = getRltList;
exp.getCardPool = getCardPool;
exp.replaceCards = replaceCards;
